package edu.ynu.se.xiecheng.achitectureclass.service;

import edu.ynu.se.xiecheng.achitectureclass.constant.YingShiConstants;
import edu.ynu.se.xiecheng.achitectureclass.dto.YingShiTokenRequest;
import edu.ynu.se.xiecheng.achitectureclass.dto.YingShiTokenResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class YingShiTokenService {
    private final RestTemplate restTemplate;
    
    private volatile String accessToken;
    private volatile LocalDateTime tokenExpireTime;
    private volatile LocalDateTime lastTokenFetchTime;
    
    private static final int REFRESH_BEFORE_EXPIRY_MINUTES = 5;  // 提前5分钟刷新
    private static final int MIN_TOKEN_FETCH_INTERVAL_MINUTES = 1;  // 最小获取间隔1分钟
    
    @PostConstruct
    public void init() {
        refreshToken();  // 应用启动时获取token
    }
    
    @Scheduled(fixedRate = 60000)  // 每分钟检查一次
    public void scheduleTokenRefresh() {
        try {
            if (shouldRefreshToken()) {
                log.info("计划的萤石token刷新被触发");
                refreshToken();
            }
        } catch (Exception e) {
            log.error("计划的萤石token刷新失败", e);
        }
    }
    
    private synchronized void refreshToken() {
        if (lastTokenFetchTime != null && 
            ChronoUnit.MINUTES.between(lastTokenFetchTime, LocalDateTime.now()) < MIN_TOKEN_FETCH_INTERVAL_MINUTES) {
            log.warn("=== 尝试过于频繁地获取萤石token！跳过刷新 ===");
            return;
        }
        
        try {
            log.warn("=== 获取新萤石token ===");
            YingShiTokenResponse response = getToken();
            
            if (!"200".equals(response.getCode())) {
                throw new RuntimeException("获取萤石token失败: " + response.getMsg());
            }
            
            this.accessToken = response.getData().getAccessToken();
            this.tokenExpireTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(response.getData().getExpireTime()),
                ZoneId.systemDefault()
            );
            this.lastTokenFetchTime = LocalDateTime.now();
            
            log.warn("=== 新萤石token获取时间: {}, 将在: {}过期 ===", 
                    lastTokenFetchTime, tokenExpireTime);
        } catch (Exception e) {
            log.error("萤石Token刷新失败", e);
            throw e;
        }
    }
    
    private YingShiTokenResponse getToken() {
        try {
            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            // 设置请求体
            YingShiTokenRequest request = new YingShiTokenRequest();
            request.setAccountId(YingShiConstants.ACCOUNT_ID);
            
            // 创建请求实体
            HttpEntity<YingShiTokenRequest> requestEntity = new HttpEntity<>(request, headers);
            
            log.info("发送萤石token请求到: {}", YingShiConstants.TOKEN_URL);
            
            // 发送请求
            ResponseEntity<YingShiTokenResponse> response = restTemplate.exchange(
                YingShiConstants.TOKEN_URL,
                HttpMethod.POST,
                requestEntity,
                YingShiTokenResponse.class
            );
            
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                log.info("成功获取萤石token，将在: {} 过期", 
                    LocalDateTime.ofInstant(
                        Instant.ofEpochMilli(response.getBody().getData().getExpireTime()),
                        ZoneId.systemDefault()
                    )
                );
                return response.getBody();
            }
            
            throw new RuntimeException("获取萤石token失败: 响应体为空");
        } catch (Exception e) {
            log.error("获取萤石token失败", e);
            throw new RuntimeException("获取萤石token失败: " + e.getMessage());
        }
    }
    
    public String getAccessToken() {
        if (isTokenValid()) {
            long minutesUntilExpiry = ChronoUnit.MINUTES.between(LocalDateTime.now(), tokenExpireTime);
            log.warn("=== 使用缓存的萤石token, 还有 {} 分钟过期, 过期时间: {} ===", 
                    minutesUntilExpiry, tokenExpireTime);
            return accessToken;
        }
        
        synchronized (this) {
            if (isTokenValid()) {
                return accessToken;
            }
            refreshToken();
            return this.accessToken;
        }
    }
    
    private boolean isTokenValid() {
        if (accessToken == null || tokenExpireTime == null) {
            log.debug("萤石Token未初始化");
            return false;
        }
        
        LocalDateTime now = LocalDateTime.now();
        boolean valid = now.isBefore(tokenExpireTime.minusMinutes(REFRESH_BEFORE_EXPIRY_MINUTES));
        
        if (!valid) {
            log.debug("萤石Token已过期或即将过期，过期时间: {}, 当前时间: {}", tokenExpireTime, now);
        }
        
        return valid;
    }
    
    private boolean shouldRefreshToken() {
        if (accessToken == null || tokenExpireTime == null) {
            return true;
        }
        
        LocalDateTime refreshTime = tokenExpireTime.minusMinutes(REFRESH_BEFORE_EXPIRY_MINUTES);
        return LocalDateTime.now().isAfter(refreshTime);
    }
}
